package com.mindskip.xzs.service.impl;

import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.data.TextRenderData;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mindskip.xzs.domain.Department;
import com.mindskip.xzs.domain.ExamPaper;
import com.mindskip.xzs.domain.ExamPaperAnswer;
import com.mindskip.xzs.domain.ExamPaperAnswerInfo;
import com.mindskip.xzs.domain.ExamPaperQuestionCustomerAnswer;
import com.mindskip.xzs.domain.Question;
import com.mindskip.xzs.domain.User;
import com.mindskip.xzs.domain.enums.ExamPaperAnswerStatusEnum;
import com.mindskip.xzs.domain.enums.QuestionTypeEnum;
import com.mindskip.xzs.domain.exam.ExamPaperTitleItemObject;
import com.mindskip.xzs.domain.other.ExamPaperAnswerUpdate;
import com.mindskip.xzs.domain.other.KeyValue;
import com.mindskip.xzs.exception.BusinessException;
import com.mindskip.xzs.repository.ExamPaperAnswerMapper;
import com.mindskip.xzs.repository.ExamPaperMapper;
import com.mindskip.xzs.repository.QuestionMapper;
import com.mindskip.xzs.service.DepartmentService;
import com.mindskip.xzs.service.ExamPaperAnswerService;
import com.mindskip.xzs.service.ExamPaperQuestionCustomerAnswerService;
import com.mindskip.xzs.service.NewUserService;
import com.mindskip.xzs.service.TextContentService;
import com.mindskip.xzs.utility.DateTimeUtil;
import com.mindskip.xzs.utility.ExamUtil;
import com.mindskip.xzs.utility.JsonUtil;
import com.mindskip.xzs.viewmodel.admin.word.EmpExamResultForWord;
import com.mindskip.xzs.viewmodel.student.exam.ExamPaperSubmitItemVM;
import com.mindskip.xzs.viewmodel.student.exam.ExamPaperSubmitVM;
import com.mindskip.xzs.viewmodel.student.exampaper.ExamPaperAnswerPageVM;
import com.mindskip.xzs.viewmodel.student.exampaper.ExamPaperAnswerReq;
import com.mindskip.xzs.viewmodel.wx.student.answer.ExamPaperAnswerPageRes;
import com.mindskip.xzs.viewmodel.wx.student.answer.ExamPaperAnswerSearchPageRes;

import cn.hutool.core.collection.CollectionUtil;
import lombok.SneakyThrows;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@Service
public class ExamPaperAnswerServiceImpl extends BaseServiceImpl<ExamPaperAnswer> implements ExamPaperAnswerService {

    private final ExamPaperAnswerMapper examPaperAnswerMapper;
    private final ExamPaperMapper examPaperMapper;
    private final TextContentService textContentService;
    private final QuestionMapper questionMapper;
    private final ExamPaperQuestionCustomerAnswerService examPaperQuestionCustomerAnswerService;
    @Resource
    private NewUserService newUserService;
    @Resource
    private DepartmentService departmentService;

    @Autowired
    public ExamPaperAnswerServiceImpl(ExamPaperAnswerMapper examPaperAnswerMapper, ExamPaperMapper examPaperMapper, TextContentService textContentService, QuestionMapper questionMapper, ExamPaperQuestionCustomerAnswerService examPaperQuestionCustomerAnswerService) {
        super(examPaperAnswerMapper);
        this.examPaperAnswerMapper = examPaperAnswerMapper;
        this.examPaperMapper = examPaperMapper;
        this.textContentService = textContentService;
        this.questionMapper = questionMapper;
        this.examPaperQuestionCustomerAnswerService = examPaperQuestionCustomerAnswerService;
    }

    @Override
    public PageInfo<ExamPaperAnswerPageRes> studentPage(ExamPaperAnswerPageVM requestVM) {
        PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(),"a.id desc");
        List<ExamPaperAnswerPageRes> answerList = examPaperAnswerMapper.studentPage(requestVM);
        if (CollectionUtil.isEmpty(answerList)) {
            return new PageInfo<ExamPaperAnswerPageRes>();
        }
        answerList.forEach(res -> {
            if (res.getPaperScoreInt() != null) {
                res.setPaperScore(ExamUtil.scoreToVM(res.getPaperScoreInt()));
            } else {
                res.setPaperScore("0");
            }
            if (res.getSystemScoreInt() != null) {
                res.setSystemScore(ExamUtil.scoreToVM(res.getSystemScoreInt()));
            } else {
                res.setSystemScore("0");
            }
            if (res.getUserScoreInt() != null) {
                res.setUserScore(ExamUtil.scoreToVM(res.getUserScoreInt()));
            } else {
                res.setUserScore("0");
            }
            if (res.getDoTimeInt() != null) {
                res.setDoTime(ExamUtil.changeTimeFormat(res.getDoTimeInt()));
            } else {
                res.setDoTime("0秒");
            }
        });
        return new PageInfo<>(answerList);
    }

    @Override
    public PageInfo<ExamPaperAnswerSearchPageRes> studentPageSearch(ExamPaperAnswerReq req) {
        PageHelper.startPage(req.getPageIndex(), req.getPageSize(),"a.id desc");
        List<ExamPaperAnswerSearchPageRes> answerList = examPaperAnswerMapper.studentPageSearch(req);
        if (CollectionUtil.isEmpty(answerList)) {
            return new PageInfo<ExamPaperAnswerSearchPageRes>();
        }
        answerList.forEach(res -> {
            if (res.getPaperScoreInt() != null) {
                res.setPaperScore(ExamUtil.scoreToVM(res.getPaperScoreInt()));
            } else {
                res.setPaperScore("0");
            }
            if (res.getSystemScoreInt() != null) {
                res.setSystemScore(ExamUtil.scoreToVM(res.getSystemScoreInt()));
            } else {
                res.setSystemScore("0");
            }
            if (res.getUserScoreInt() != null) {
                res.setUserScore(ExamUtil.scoreToVM(res.getUserScoreInt()));
            } else {
                res.setUserScore("0");
            }
            if (res.getDoTimeInt() != null) {
                res.setDoTime(ExamUtil.changeTimeFormat(res.getDoTimeInt()));
            } else {
                res.setSuggestTime("0秒");
            }
        });
        return new PageInfo<>(answerList);
    }


    @Override
    public ExamPaperAnswerInfo calculateExamPaperAnswer(ExamPaperSubmitVM examPaperSubmitVM, User user) {
        ExamPaperAnswerInfo examPaperAnswerInfo = new ExamPaperAnswerInfo();
        Date now = new Date();
        ExamPaper examPaper = examPaperMapper.selectByPrimaryKey(examPaperSubmitVM.getId());
        String frameTextContent = textContentService.selectById(examPaper.getFrameTextContentId()).getContent();
        List<ExamPaperTitleItemObject> examPaperTitleItemObjects = JsonUtil.toJsonListObject(frameTextContent, ExamPaperTitleItemObject.class);
        List<Integer> questionIds = examPaperTitleItemObjects.stream().flatMap(t -> t.getQuestionItems().stream().map(q -> q.getId())).collect(Collectors.toList());
        List<Question> questions = questionMapper.selectByIds(questionIds);
        //将题目结构的转化为题目答案
        List<ExamPaperQuestionCustomerAnswer> examPaperQuestionCustomerAnswers = examPaperTitleItemObjects.stream()
                .flatMap(t -> t.getQuestionItems().stream()
                        .map(q -> {
                            Question question = questions.stream().filter(tq -> tq.getId().equals(q.getId())).findFirst().get();
                            ExamPaperSubmitItemVM customerQuestionAnswer = examPaperSubmitVM.getAnswerItems().stream()
                                    .filter(tq -> tq.getQuestionId().equals(q.getId()))
                                    .findFirst()
                                    .orElse(null);
                            return ExamPaperQuestionCustomerAnswerFromVM(question, customerQuestionAnswer, examPaper, q.getItemOrder(), user, now);
                        })
                ).collect(Collectors.toList());

        ExamPaperAnswer examPaperAnswer = ExamPaperAnswerFromVM(examPaperSubmitVM, examPaper, examPaperQuestionCustomerAnswers, user, now);
        examPaperAnswerInfo.setExamPaper(examPaper);
        examPaperAnswerInfo.setExamPaperAnswer(examPaperAnswer);
        examPaperAnswerInfo.setExamPaperQuestionCustomerAnswers(examPaperQuestionCustomerAnswers);
        return examPaperAnswerInfo;
    }

    @Override
    @Transactional
    public String judge(ExamPaperSubmitVM examPaperSubmitVM) {
        ExamPaperAnswer examPaperAnswer = examPaperAnswerMapper.selectByPrimaryKey(examPaperSubmitVM.getId());
        List<ExamPaperSubmitItemVM> judgeItems = examPaperSubmitVM.getAnswerItems().stream().filter(d -> d.getDoRight() == null).collect(Collectors.toList());
        List<ExamPaperAnswerUpdate> examPaperAnswerUpdates = new ArrayList<>(judgeItems.size());
        Integer customerScore = examPaperAnswer.getUserScore();
        Integer questionCorrect = examPaperAnswer.getQuestionCorrect();
        for (ExamPaperSubmitItemVM d : judgeItems) {
            ExamPaperAnswerUpdate examPaperAnswerUpdate = new ExamPaperAnswerUpdate();
            examPaperAnswerUpdate.setId(d.getId());
            examPaperAnswerUpdate.setCustomerScore(ExamUtil.scoreFromVM(d.getScore()));
            boolean doRight = examPaperAnswerUpdate.getCustomerScore().equals(ExamUtil.scoreFromVM(d.getQuestionScore()));
            examPaperAnswerUpdate.setDoRight(doRight);
            examPaperAnswerUpdates.add(examPaperAnswerUpdate);
            customerScore += examPaperAnswerUpdate.getCustomerScore();
            if (examPaperAnswerUpdate.getDoRight()) {
                ++questionCorrect;
            }
        }
        examPaperAnswer.setUserScore(customerScore);
        examPaperAnswer.setQuestionCorrect(questionCorrect);
        examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.Complete.getCode());
        examPaperAnswerMapper.updateByPrimaryKeySelective(examPaperAnswer);
        examPaperQuestionCustomerAnswerService.updateScore(examPaperAnswerUpdates);

        return ExamUtil.scoreToVM(customerScore);
    }

    @Override
    public ExamPaperSubmitVM examPaperAnswerToVM(Integer id) {
        ExamPaperSubmitVM examPaperSubmitVM = new ExamPaperSubmitVM();
        ExamPaperAnswer examPaperAnswer = examPaperAnswerMapper.selectByPrimaryKey(id);
        examPaperSubmitVM.setId(examPaperAnswer.getId());
        examPaperSubmitVM.setDoTime(examPaperAnswer.getDoTime());
        examPaperSubmitVM.setScore(ExamUtil.scoreToVM(examPaperAnswer.getUserScore()));
        List<ExamPaperQuestionCustomerAnswer> examPaperQuestionCustomerAnswers = examPaperQuestionCustomerAnswerService.selectListByPaperAnswerId(examPaperAnswer.getId());
        List<ExamPaperSubmitItemVM> examPaperSubmitItemVMS = examPaperQuestionCustomerAnswers.stream()
                .map(a -> examPaperQuestionCustomerAnswerService.examPaperQuestionCustomerAnswerToVM(a))
                .collect(Collectors.toList());
        examPaperSubmitVM.setAnswerItems(examPaperSubmitItemVMS);
        return examPaperSubmitVM;
    }

    @Override
    public Integer selectAllCount() {
        return examPaperAnswerMapper.selectAllCount();
    }

    @Override
    public List<Integer> selectMothCount() {
        Date startTime = DateTimeUtil.getMonthStartDay();
        Date endTime = DateTimeUtil.getMonthEndDay();
        List<KeyValue> mouthCount = examPaperAnswerMapper.selectCountByDate(startTime, endTime);
        List<String> mothStartToNowFormat = DateTimeUtil.MothStartToNowFormat();
        return mothStartToNowFormat.stream().map(md -> {
            KeyValue keyValue = mouthCount.stream().filter(kv -> kv.getName().equals(md)).findAny().orElse(null);
            return null == keyValue ? 0 : keyValue.getValue();
        }).collect(Collectors.toList());
    }


    /**
     * 用户提交答案的转化存储对象
     *
     * @param question               question
     * @param customerQuestionAnswer customerQuestionAnswer
     * @param examPaper              examPaper
     * @param itemOrder              itemOrder
     * @param user                   user
     * @param now                    now
     * @return ExamPaperQuestionCustomerAnswer
     */
    private ExamPaperQuestionCustomerAnswer ExamPaperQuestionCustomerAnswerFromVM(Question question, ExamPaperSubmitItemVM customerQuestionAnswer, ExamPaper examPaper, Integer itemOrder, User user, Date now) {
        ExamPaperQuestionCustomerAnswer examPaperQuestionCustomerAnswer = new ExamPaperQuestionCustomerAnswer();
        examPaperQuestionCustomerAnswer.setQuestionId(question.getId());
        examPaperQuestionCustomerAnswer.setExamPaperId(examPaper.getId());
        examPaperQuestionCustomerAnswer.setQuestionScore(question.getScore());
        examPaperQuestionCustomerAnswer.setItemOrder(itemOrder);
        examPaperQuestionCustomerAnswer.setCreateTime(now);
        examPaperQuestionCustomerAnswer.setCreateUser(user.getId());
        examPaperQuestionCustomerAnswer.setQuestionType(question.getQuestionType());
        examPaperQuestionCustomerAnswer.setQuestionTextContentId(question.getInfoTextContentId());
        if (null == customerQuestionAnswer) {
            examPaperQuestionCustomerAnswer.setCustomerScore(0);
        } else {
            setSpecialFromVM(examPaperQuestionCustomerAnswer, question, customerQuestionAnswer);
        }
        return examPaperQuestionCustomerAnswer;
    }

    /**
     * 判断提交答案是否正确，保留用户提交的答案
     *
     * @param examPaperQuestionCustomerAnswer examPaperQuestionCustomerAnswer
     * @param question                        question
     * @param customerQuestionAnswer          customerQuestionAnswer
     */
    private void setSpecialFromVM(ExamPaperQuestionCustomerAnswer examPaperQuestionCustomerAnswer, Question question, ExamPaperSubmitItemVM customerQuestionAnswer) {
        QuestionTypeEnum questionTypeEnum = QuestionTypeEnum.fromCode(examPaperQuestionCustomerAnswer.getQuestionType());
        switch (questionTypeEnum) {
            case SingleChoice:
            case TrueFalse:
                examPaperQuestionCustomerAnswer.setAnswer(customerQuestionAnswer.getContent());
                examPaperQuestionCustomerAnswer.setDoRight(question.getCorrect().equals(customerQuestionAnswer.getContent()));
                examPaperQuestionCustomerAnswer.setCustomerScore(examPaperQuestionCustomerAnswer.getDoRight() ? question.getScore() : 0);
                break;
            case MultipleChoice:
                String customerAnswer = ExamUtil.contentToString(customerQuestionAnswer.getContentArray());
                examPaperQuestionCustomerAnswer.setAnswer(customerAnswer);
                examPaperQuestionCustomerAnswer.setDoRight(customerAnswer.equals(question.getCorrect()));
                examPaperQuestionCustomerAnswer.setCustomerScore(examPaperQuestionCustomerAnswer.getDoRight() ? question.getScore() : 0);
                break;
            case GapFilling:
                String correctAnswer = JsonUtil.toJsonStr(customerQuestionAnswer.getContentArray() == null ? Collections.singletonList(customerQuestionAnswer.getContent()) : customerQuestionAnswer.getContentArray());
                examPaperQuestionCustomerAnswer.setAnswer(correctAnswer);
                examPaperQuestionCustomerAnswer.setCustomerScore(0);
                break;
            default:
                examPaperQuestionCustomerAnswer.setAnswer(customerQuestionAnswer.getContent());
                examPaperQuestionCustomerAnswer.setCustomerScore(0);
                break;
        }
    }

    private ExamPaperAnswer ExamPaperAnswerFromVM(ExamPaperSubmitVM examPaperSubmitVM, ExamPaper examPaper, List<ExamPaperQuestionCustomerAnswer> examPaperQuestionCustomerAnswers, User user, Date now) {
        Integer systemScore = examPaperQuestionCustomerAnswers.stream().mapToInt(a -> a.getCustomerScore()).sum();
        long questionCorrect = examPaperQuestionCustomerAnswers.stream().filter(a -> a.getCustomerScore().equals(a.getQuestionScore())).count();
        ExamPaperAnswer examPaperAnswer = new ExamPaperAnswer();
        examPaperAnswer.setDoTime(examPaperSubmitVM.getDoTime());
        examPaperAnswer.setExamPaperId(examPaper.getId());
        examPaperAnswer.setCreateUser(user.getId());
        examPaperAnswer.setCreateTime(now);
        examPaperAnswer.setQuestionCount(examPaper.getQuestionCount());
        examPaperAnswer.setPaperScore(examPaper.getScore());
        examPaperAnswer.setSystemScore(systemScore);
        examPaperAnswer.setUserScore(systemScore);
        examPaperAnswer.setExamId(examPaperSubmitVM.getExamId());
        examPaperAnswer.setQuestionCorrect((int) questionCorrect);
        boolean needJudge = examPaperQuestionCustomerAnswers.stream().anyMatch(d -> QuestionTypeEnum.needSaveTextContent(d.getQuestionType()));
        if (needJudge) {
            examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.WaitJudge.getCode());
        } else {
            examPaperAnswer.setStatus(ExamPaperAnswerStatusEnum.Complete.getCode());
        }
        return examPaperAnswer;
    }


    @Override
    public PageInfo<ExamPaperAnswer> adminPage(com.mindskip.xzs.viewmodel.admin.paper.ExamPaperAnswerPageRequestVM requestVM) {
        return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() ->
                examPaperAnswerMapper.adminPage(requestVM));
    }

    @Override
    @SneakyThrows
    public void exportEmployeeResultListWord(Long userId, Long deptId, String startTime, String endTime, String createDate,
                                             String category, HttpServletResponse response) {
        User employee = newUserService.getById(userId);
        if (employee == null) {
            throw new BusinessException("员工不存在，请核对后再试");
        }
        Department department = departmentService.getById(deptId);
        if (department == null) {
            throw new BusinessException("部门不存在，请核对后再试");
        }

        ExamPaperAnswerReq req = new ExamPaperAnswerReq();
        req.setStatus(ExamPaperAnswerStatusEnum.Complete.getCode());
        req.setUserId(Math.toIntExact(userId));
        req.setDeptId(deptId);
        req.setPageIndex(1);
        req.setPageSize(10000);
        req.setTeacherStartTime(startTime);
        req.setTeacherEndTime(endTime);
        req.setCategory(category);
        List<ExamPaperAnswerSearchPageRes> resultList = studentPageSearch(req).getList();

        // word模板
        //获得文件流时，因为读取的文件是在打好jar文件里面，不能直接通过文件资源路径拿到文件，但是可以在jar包中拿到文件流
        //ResourcePatternResolver的实现方法，可以匹配到各种部署时的各种文件类型例如war，jar，zip等等findPathMatchingResources
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        org.springframework.core.io.Resource[] resources = resolver.getResources("classpath:/file/template/员工个人教育培训档案模板.docx");
        org.springframework.core.io.Resource resource = resources[0];
        InputStream inputStream = resource.getInputStream();

        //File templateFile = ResourceUtils.getFile("classpath:/file/template/员工个人教育培训档案模板.docx");
        Map<String, Object> datas = new HashMap<String, Object>();
        LocalDateTime createDateTime = LocalDateTime.parse(createDate + " 00:00:00", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        datas.put("createYear", new TextRenderData("000000", String.valueOf(createDateTime.getYear())));
        datas.put("createMonth", new TextRenderData("000000", String.valueOf(createDateTime.getMonthValue())));
        datas.put("createDay", new TextRenderData("000000", String.valueOf(createDateTime.getDayOfMonth())));
        datas.put("empName", new TextRenderData("000000", employee.getUserName()));
        datas.put("empDept", new TextRenderData("000000", department.getName()));
        /*      datas.put("createYear", Texts.of("内容1").style(style).create());  //字体、颜色
        datas.put("createMonth", Texts.of("超链接").link("http://deepoove.com").style(style).create()); //链接
        datas.put("image", Pictures.ofUrl("http://deepoove.com/images/icecream.png").size(100, 100).create()); // 图片*/

        // 插件列表,可以去官网查看，有列循环，还有行循环，这里是行循环实例
        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
        //这里可以指定一个config类，用来指定一些规则，也可以改变模板中{{}}的这种格式
        Configure config = Configure.builder()
                .bind("lists", policy).build();
        List<EmpExamResultForWord> rowList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(resultList)) {
            resultList.forEach(result -> {
                if (StringUtils.isNotBlank(result.getExamName())) {
                    Integer passScore = result.getPassScore();
                    if (passScore != null) {
                        passScore = passScore * 10;
                    }
                    String teacherTime;
                    if (result.getTeacherTime() == null) {
                        teacherTime = "未知";
                    } else {
                        teacherTime = result.getTeacherTime().format(DateTimeFormatter.ISO_DATE);
                    }
                    rowList.add(
                            new EmpExamResultForWord()
                                    .setDate(teacherTime)
                                    .setAddress("玉溪医药内部")
                                    .setTeacher(Optional.ofNullable(result.getTeacherName()).orElse(""))
                                    .setExamName(result.getExamName())
                                    .setExamTime(result.getSuggestTime() == null ? "未知" : result.getSuggestTime() + "分钟")
                                    .setExamType("培训后考试")
                                    .setExamResult(result.getUserScoreInt() >= Optional.ofNullable(passScore).orElse(600) ? "合格" : "不合格")
                                    .setRemark("无")
                    );
                }
            });
        }
        datas.put("lists", rowList);
        XWPFTemplate compile = XWPFTemplate.compile(inputStream, config);
        compile.render(datas);
        // 浏览器端下载
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/msword");
        String fileName = String.format("YXYYPF-YP-QR-%s%s教育培训档案.docx", employee.getId(), employee.getUserName());
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        compile.write(response.getOutputStream());
    }
}
